package com.usian.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.usian.mapper.*;
import com.usian.pojo.*;
import com.usian.redis.RedisClient;
import com.usian.service.ItemService;
import com.usian.utils.IDUtils;
import com.usian.utils.PageResult;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class TemServiceImpl implements ItemService {

    @Autowired
    private TbItemMapper tbItemMapper;

    @Autowired
    TbItemDescMapper tbItemDescMapper;

    @Autowired
    TbItemParamItemMapper tbItemParamItemMapper;

    @Autowired
    TbItemParamMapper tbItemParamMapper;

    @Autowired
    TbItemCatMapper tbItemCatMapper;

    @Autowired
    AmqpTemplate amqpTemplate;

    @Autowired
    RedisClient redisClient;

    @Autowired
    TbOrderItemMapper tbOrderItemMapper;

    //redis的set方法
    @Value("${ITEM_INFO}")
    private String ITEM_INFO;

    @Value("${BASE}")
    private String BASE;

    @Value("${DESC}")
    private String DESC;

    @Value("${PARAM}")
    private String PARAM;

    @Value("${ITEM_INFO_EXPIRE}")
    private Integer ITEM_INFO_EXPIRE;

    //redis的setnx方法
    @Value("${SETNX_BASC_LOCK_KEY}")
    private String SETNX_BASC_LOCK_KEY;

    @Value("${SETNX_DESC_LOCK_KEY}")
    private String SETNX_DESC_LOCK_KEY;

    @Value("${SETNX_PARAM_LOCK_KEY}")
    private String SETNX_PARAM_LOCK_KEY;

    /**
     * 删除商品信息
     *
     * @param itemId
     * @return
     */
    @Override
    public Integer deleteTbItem(Long itemId) {

        TbItemParamItemExample parmExample = new TbItemParamItemExample();
        TbItemParamItemExample.Criteria parmCriteria = parmExample.createCriteria();
        parmCriteria.andItemIdEqualTo(itemId);
        Integer itemParamItmeNum = tbItemParamItemMapper.deleteByExample(parmExample);

        Integer tbitemDescNum = tbItemDescMapper.deleteByPrimaryKey(itemId);

        TbItem item = tbItemMapper.selectByPrimaryKey(itemId);
        item.setStatus((byte) 3);
        Integer tbItemNum = tbItemMapper.updateByPrimaryKeySelective(item);

        //通过rabbitmq发送消息   只存放商品id
        amqpTemplate.convertAndSend("exchange_usian", "item.delete", itemId);
        return tbItemNum + tbitemDescNum + itemParamItmeNum;
    }

    /**
     * 修改商品信息
     *
     * @param tbItem
     * @param desc
     * @param itemParams
     * @return
     */
    @Override
    public Integer updateTbItem(TbItem tbItem, String desc, String itemParams) {
        //补齐 Tbitem 数据
        Date date = new Date();
        tbItem.setUpdated(date);
        tbItem.setPrice(tbItem.getPrice() * 100);
        Integer tbItemNum = tbItemMapper.updateByPrimaryKeySelective(tbItem);

        //补齐商品描述对象
        TbItemDesc tbItemDesc = new TbItemDesc();
        tbItemDesc.setItemId(tbItem.getId());
        tbItemDesc.setItemDesc(desc);
        tbItemDesc.setUpdated(date);
        Integer tbitemDescNum = tbItemDescMapper.updateByPrimaryKeySelective(tbItemDesc);
        Integer example = null;
        //补齐商品规格参数
        if (itemParams != null) {
            TbItemParamItemExample itemParamItemExample = new TbItemParamItemExample();
            TbItemParamItemExample.Criteria criteria = itemParamItemExample.createCriteria();
            criteria.andItemIdEqualTo(tbItem.getId());
            TbItemParamItem tbItemParamItem = new TbItemParamItem();
            tbItemParamItem.setItemId(tbItem.getId());
            tbItemParamItem.setParamData(itemParams);
            tbItemParamItem.setUpdated(date);
            example = tbItemParamItemMapper.updateByExampleSelective(tbItemParamItem, itemParamItemExample);
        }else {
            example = 1;
        }
        //通过rabbitmq发送消息   只存放商品id
        amqpTemplate.convertAndSend("exchange_usian", "item.update", tbItem.getId());
        return tbItemNum + tbitemDescNum + example;
    }

    /**
     * 根据商品 ID 查询商品，商品分类，商品描述，商品规格参数
     *
     * @param itemId
     * @return
     */
    @Override
    public Map<String, Object> preUpdateItem(Long itemId) {
        Map<String, Object> map = new HashMap<>();
        //根据商品 ID 查询商品
        TbItem item = this.tbItemMapper.selectByPrimaryKey(itemId);
        item.setPrice(item.getPrice() / 100);
        map.put("item", item);
        //根据商品 ID 查询商品描述
        TbItemDesc itemDesc = this.tbItemDescMapper.selectByPrimaryKey(itemId);
        if (itemDesc != null) {
            map.put("itemDesc", itemDesc.getItemDesc());
        } else {
            map.put("itemDesc", "");
        }
        //根据商品 ID 查询商品类目
        TbItemCat itemCat = this.tbItemCatMapper.selectByPrimaryKey(item.getCid());
        map.put("itemCat", itemCat.getName());
        //根据商品 ID 查询商品规格信息
        TbItemParamItemExample example = new TbItemParamItemExample();
        TbItemParamItemExample.Criteria criteria = example.createCriteria();
        criteria.andItemIdEqualTo(itemId);
        List<TbItemParamItem> list =
                this.tbItemParamItemMapper.selectByExampleWithBLOBs(example);
        if (list != null && list.size() > 0) {
            map.put("itemParamItem", list.get(0).getParamData());
        }
        return map;
    }


    /**
     * 分页查询
     *
     * @param page
     * @param rows
     * @return
     */
    @Override
    public PageResult selectTbItemAllByPage(Integer page, Integer rows) {
        PageHelper.startPage(page, rows);
        TbItemExample example = new TbItemExample();
        TbItemExample.Criteria criteria = example.createCriteria();
        criteria.andStatusEqualTo((byte) 1);
        List<TbItem> list = this.tbItemMapper.selectByExample(example);
        PageInfo<TbItem> pageInfo = new PageInfo<>(list);
        PageResult pageResult = new PageResult();
        pageResult.setPageIndex(pageInfo.getPageNum());
        pageResult.setTotalPage(pageInfo.getPages());

        for (TbItem tbItem : pageInfo.getList()) {
            tbItem.setPrice(tbItem.getPrice() / 100);
        }
        pageResult.setResult(pageInfo.getList());
        return pageResult;
    }

    /**
     * 添加商品信息
     *
     * @param tbItem
     * @param desc
     * @param itemParams
     * @return
     */
    @Override
    public Integer insertTbItem(TbItem tbItem, String desc, String itemParams) {
        //补齐 Tbitem 数据
        Long itemId = IDUtils.genItemId();
        Date date = new Date();
        tbItem.setId(itemId);
        tbItem.setStatus((byte) 1);
        tbItem.setUpdated(date);
        tbItem.setCreated(date);
        tbItem.setPrice(tbItem.getPrice() * 100);
        Integer tbItemNum = tbItemMapper.insertSelective(tbItem);

        //补齐商品描述对象
        TbItemDesc tbItemDesc = new TbItemDesc();
        tbItemDesc.setItemId(itemId);
        tbItemDesc.setItemDesc(desc);
        tbItemDesc.setCreated(date);
        tbItemDesc.setUpdated(date);
        Integer tbitemDescNum = tbItemDescMapper.insertSelective(tbItemDesc);

        //补齐商品规格参数
        TbItemParamItem tbItemParamItem = new TbItemParamItem();
        tbItemParamItem.setItemId(itemId);
        tbItemParamItem.setParamData(itemParams);
        tbItemParamItem.setUpdated(date);
        tbItemParamItem.setCreated(date);
        Integer itemParamItmeNum =
                tbItemParamItemMapper.insertSelective(tbItemParamItem);

        //通过rabbitmq发送消息   只存放商品id
        amqpTemplate.convertAndSend("exchange_usian", "item.insert", itemId);
        return tbItemNum + tbitemDescNum + itemParamItmeNum;
    }

    /**
     * 6.商品详情页商品介绍接口
     *
     * @param itemId
     * @return
     */
    @Override
    public TbItemDesc selectItemDescByItemId(Long itemId) {
        //先从redis缓存中查询
        TbItemDesc tbItemDesc = (TbItemDesc) redisClient.get(ITEM_INFO + ":" + itemId + ":" + DESC);
        //查到数据直接返回数据
        if (tbItemDesc != null) {
            return tbItemDesc;
        }
        /*****************解决缓存击穿***************/
        if (redisClient.setnx(SETNX_DESC_LOCK_KEY + ":" + itemId, itemId, 30L)) {
            //如果缓存中没有就去查数据库
            tbItemDesc = tbItemDescMapper.selectByPrimaryKey(itemId);
            //如果数据库为空就缓存一个空对象
            if (tbItemDesc != null) {
                //数据库查到值 缓存到redis
                redisClient.set(ITEM_INFO + ":" + itemId + ":" + DESC, tbItemDesc);
                //设置过期时间
                redisClient.expire(ITEM_INFO + ":" + itemId + ":" + DESC, ITEM_INFO_EXPIRE);
                return tbItemDesc;
            }
            //数据库如果没有就缓存一个对象
            redisClient.set(ITEM_INFO + ":" + itemId + ":" + DESC, tbItemDesc);
            //设置过期时间
            redisClient.expire(ITEM_INFO + ":" + itemId + ":" + DESC, ITEM_INFO_EXPIRE);
            return tbItemDesc;
        } else {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return selectItemDescByItemId(itemId);
        }
    }

    /**
     * 商品详情页规格参数接口
     *
     * @param itemId
     * @return
     */
    @Override
    public TbItemParamItem selectTbItemParamItemByItemId(Long itemId) {
        //先从redis缓存中查询
        TbItemParamItem tbItemParamItem = (TbItemParamItem) redisClient.get(ITEM_INFO + ":" + itemId + ":" + PARAM);
        //缓存中查到数据直接返回
        if (tbItemParamItem != null) {
            return tbItemParamItem;
        }
        /*****************解决缓存击穿***************/
        if (redisClient.setnx(SETNX_PARAM_LOCK_KEY + ":" + itemId, itemId, 30L)) {
            //如果缓存中没有就去查数据库
            TbItemParamItemExample tbItemParamItemExample = new TbItemParamItemExample();
            TbItemParamItemExample.Criteria criteria = tbItemParamItemExample.createCriteria();
            criteria.andItemIdEqualTo(itemId);
            tbItemParamItem = tbItemParamItemMapper.selectByExampleWithBLOBs(tbItemParamItemExample).get(0);

            //如果数据库也没有就存一个空对象
            if (tbItemParamItem == null) {
                redisClient.set(ITEM_INFO + ":" + itemId + ":" + PARAM, new TbItemParamItem(1L, "系统繁忙"));
                //设置过期时间
                redisClient.expire(ITEM_INFO + ":" + itemId + ":" + PARAM, 30);
                return tbItemParamItem;
            }
            //从数据库查到数据缓存到redis
            redisClient.set(ITEM_INFO + ":" + itemId + ":" + PARAM, tbItemParamItem);
            redisClient.expire(ITEM_INFO + ":" + itemId + ":" + PARAM, ITEM_INFO_EXPIRE);
            return tbItemParamItem;
        } else {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return selectTbItemParamItemByItemId(itemId);
        }
    }

    /**
     * 修改商品库存数量
     *
     * @param orderId
     * @return
     */
    @Override
    public Integer updateTbItemByOrderId(String orderId) {
        TbOrderItemExample tbOrderItemExample = new TbOrderItemExample();
        TbOrderItemExample.Criteria criteria = tbOrderItemExample.createCriteria();
        criteria.andOrderIdEqualTo(orderId);
        List<TbOrderItem> tbOrderItemList =
                tbOrderItemMapper.selectByExample(tbOrderItemExample);
        int result = 0;
        for (TbOrderItem orderItem : tbOrderItemList) {

            TbItem item = tbItemMapper.selectByPrimaryKey(Long.valueOf(orderItem.getItemId()));
            item.setNum(item.getNum() - orderItem.getNum());
             result = tbItemMapper.updateByPrimaryKeySelective(item);
        }
        return result;
    }

    /**
     * 5.商品详情接口
     *
     * @param itemId
     * @return
     */
    @Override
    public TbItem selectItemInfo(Long itemId) {

        //先从redis缓存中查询
        TbItem tbItem = (TbItem) redisClient.get(ITEM_INFO + ":" + itemId + ":" + BASE);
        if (tbItem != null) {
            return tbItem;
        }
        /*****************解决缓存击穿***************/
        if (redisClient.setnx(SETNX_BASC_LOCK_KEY + ":" + itemId, itemId, 30L)) {

            //缓存中没有再去查询数据库
            tbItem = tbItemMapper.selectByPrimaryKey(itemId);
            /********************解决缓存穿透************************/
            if (tbItem == null) {
                //数据库没有缓存一个空数据
                redisClient.set(ITEM_INFO + ":" + itemId + ":" + BASE, new TbItem(1L, "系统繁忙"));
                //设置缓存有效期
                redisClient.expire(ITEM_INFO + ":" + itemId + ":" + BASE, 30);
                return tbItem;
            }

            //数据库查到数据 存到redis缓存
            redisClient.set(ITEM_INFO + ":" + itemId + ":" + BASE, tbItem);
            //设置过期时间 正好24小时
            redisClient.expire(ITEM_INFO + ":" + itemId + ":" + BASE, ITEM_INFO_EXPIRE);
            return tbItem;
        } else {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return selectItemInfo(itemId);
        }
    }


}
